package generate

import (
	"github.com/rs/xid"
	"gopkg.in/yaml.v3"
	"io"
	v1 "k8s.io/api/apps/v1"
	v13 "k8s.io/api/core/v1"
	v12 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"operator/cicd/util"
	"unsafe"
)

type DeploymentGenerator struct {
	config *util.CICDConfig
}

func (dg *DeploymentGenerator) Generate(r []byte, w io.Writer) (int, error) {
	template := new(DeploymentTemplate)
	err := yaml.Unmarshal(r, template)
	if err != nil {
		return 0, err
	}

	id := dg.config.ID
	if template.NameSpace == "" {
		template.NameSpace = "default"
	}
	if template.Name == "" {
		template.Name = "deploy-" + xid.New().String()[:5]
	}
	if template.Count == 0 {
		template.Count = 1
	}
	ps := make([]v13.ContainerPort, 0, 10)
	if len(template.Ports) > 0 {
		for _, port := range template.Ports {
			pt := *(*v13.ContainerPort)(unsafe.Pointer(&port))
			ps = append(ps, pt)
		}
	}

	deployment := v1.Deployment{
		ObjectMeta: v12.ObjectMeta{
			Name:      template.Name,
			Namespace: template.NameSpace,
			Labels:    template.Labels,
		},
		Spec: v1.DeploymentSpec{
			Replicas: &template.Count,
			Selector: &v12.LabelSelector{
				MatchLabels: map[string]string{
					"genid": getLabelValue(id),
				},
			},
			Template: v13.PodTemplateSpec{
				ObjectMeta: v12.ObjectMeta{
					Labels: map[string]string{
						"genid": getLabelValue(id),
					},
				},
				Spec: v13.PodSpec{
					Containers: []v13.Container{
						{
							Name:  "container-" + id[:5],
							Image: dg.config.ImageName + ":" + dg.config.Version,
							Ports: ps,
						},
					},
				},
			},
		},
	}

	if len(template.OtherSpec) != 0 {
		spec, err := util.ConvertYamlToPodSpec(template.OtherSpec)
		if err != nil {
			return 0, err
		}

		util.CopySpec(spec, &deployment.Spec.Template.Spec)
	}

	count, err := util.WriteStruct(&deployment, w)

	return count, nil
}

//func (dg *DeploymentGenerator) GenerateWithReader(r io.Reader, w io.Writer) (int, error) {
//
//}

func NewDeploymentGenerator(config *util.CICDConfig) *DeploymentGenerator {
	dg := DeploymentGenerator{
		config: config,
	}

	return &dg
}
